﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace FishEyeWPF
{
    public class FishEyeBehavior : Behavior<FrameworkElement>
    {
        double width;
        double height;
        bool enabled;
        Point lastMousePosition;

        protected override void OnAttached()
        {
            base.OnAttached();

            width = AssociatedObject.Width;
            height = AssociatedObject.Height;

            Application.Current.MainWindow.CaptureMouse();
            Application.Current.MainWindow.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove);

            (AssociatedObject.Parent as FrameworkElement).MouseEnter += (s, e) =>
                {
                    enabled = true;
                };
            (AssociatedObject.Parent as FrameworkElement).MouseLeave += (s, e) =>
                {
                    enabled = false;
                };
        }

        protected override void OnDetaching()
        {
            Application.Current.MainWindow.ReleaseMouseCapture();

            base.OnDetaching();
        }

        void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            Point globalMousePosition = e.GetPosition(sender as FrameworkElement);
            if (lastMousePosition == globalMousePosition)
            {
                return;
            }
            lastMousePosition = globalMousePosition;

            Point mousePosition = e.GetPosition(AssociatedObject);
            mousePosition = AssociatedObject.TranslatePoint(mousePosition, AssociatedObject);
            
            double distance;
            if (Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                distance = mousePosition.X - AssociatedObject.ActualWidth / 2.0;
            }
            else
            {
                distance = mousePosition.Y - AssociatedObject.ActualHeight / 2.0;
            }

            double scale;
            if (!enabled || Math.Abs(distance) > MaxDistance)
            {
                // Reset Size
                scale = 1;
            }
            else
            {
                scale = MaxScale * (1 - (Math.Abs(distance) / MaxDistance));

                if (scale < MinScale)
                {
                    scale = MinScale;
                }
            }

            AssociatedObject.Width = width * scale;
            AssociatedObject.Height = height * scale;
        }

        #region Properties

        public double MinScale
        {
            get { return (double)GetValue(MinScaleProperty); }
            set { SetValue(MinScaleProperty, value); }
        }

        public static readonly DependencyProperty MinScaleProperty =
            DependencyProperty.Register(
                "MinScale",
                typeof(double),
                typeof(FishEyeBehavior),
                new UIPropertyMetadata(1.0));

        public double MaxScale
        {
            get { return (double)GetValue(MaxScaleProperty); }
            set { SetValue(MaxScaleProperty, value); }
        }

        public static readonly DependencyProperty MaxScaleProperty =
            DependencyProperty.Register(
                "MaxScale",
                typeof(double),
                typeof(FishEyeBehavior),
                new UIPropertyMetadata(3.0));

        public double MaxDistance
        {
            get { return (double)GetValue(MaxDistanceProperty); }
            set { SetValue(MaxDistanceProperty, value); }
        }

        public static readonly DependencyProperty MaxDistanceProperty =
            DependencyProperty.Register(
                "MaxDistance",
                typeof(double),
                typeof(FishEyeBehavior),
                new UIPropertyMetadata(300.0));

        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register(
                "Orientation",
                typeof(Orientation),
                typeof(FishEyeBehavior),
                new UIPropertyMetadata(Orientation.Horizontal));

        #endregion

    }
}